let Vm;
(function() {
	let _calllback;
	let stack = []

	function getValue(name) {
		for (let i = stack.length - 1; i >= 0; i--) {
			let Var = stack[i];
			if (Var.name === name) {
				if (Var.value === undefined) {
					throw Error(name + '未赋值')
				}
				return stack[i].value
			}
		}
		throw Error(name + '未定义')
	}

	function defineValue(name, value) {
		stack.push({
			name: name,
			value: value
		})
	}

	function setValue(name, value) {
		for (let i = stack.length - 1; i >= 0; i--) {
			let Var = stack[i];
			if (Var.name === name) {
				stack[i].value = value;
				return;
			}
		}
		throw Error(name + '未定义')
	}

	function judge(ast) {
		if (condition(ast.condition)) {
			program(ast.body)
		} else {
			if (ast.elsebody) {
				program(ast.elsebody)
			}
		}
	}

	function loop(ast) {
		while (condition(ast.condition)) {
			program(ast.body)
		}
	}

	function expression(ast) {
		if (ast.type === 'number') {
			return ast.value
		} else if (ast.type === 'variable') {
			return getValue(ast.value)
		} else if (ast.type === 'funcall') {
			return funcall(ast)
		} else {
			let left = expression(ast.left)
			let right = expression(ast.right)
			let operator = ast.operator
			if (operator === '+') return left + right;
			if (operator === '-') return left - right;
			if (operator === '*') return left * right;
			if (operator === '/') return left / right;

		}
	}

	function condition(ast) {
		let left = ast.left
		let right = ast.right
		if (left.type === 'condition') {
			left = condition(left)
		} else {
			left = expression(left)
		}
		if (right.type === 'condition') {
			right = condition(right)
		} else {
			right = expression(right)
		}
		let operator = ast.operator
		if (operator === 'or') return left || right;
		if (operator === 'and') return left && right;
		if (operator === '>') return left > right;
		if (operator === '>=') return left >= right;
		if (operator === '<') return left < right;
		if (operator === '<=') return left <= right;
		if (operator === '=') return left == right;
	}

	function funcall(ast) {
		let var_count = 0;
		let parameter = ast.parameter
		let fun = getValue(ast.name)
		fun.parameter.forEach((_ast, index) => {
			if (parameter.length < index + 1) {
				throw Error('函数' + fun.name + '传参过多')
			} else {
				defineValue(_ast.name, expression(parameter[index]))
				var_count++
			}
		})
		var_count += program(fun.body, true)
		let value = expression(fun['return'])
		//释放变量
		while (var_count > 0) {
			stack.pop()
			var_count--
		}
		return value
	}

	function print(ast) {
		let resut = expression(ast.value)
		if (_calllback) {
			_calllback(resut)
		} else {
			console.log(expression(ast.value))
		}
	}

	function program(ast, reserve) {
		let var_count = 0;
		for (let i = 0; i < ast.length; i++) {
			let _ast = ast[i]
			if (_ast.type == 'dim') {
				defineValue(_ast.name)
				var_count++
			}
			if (_ast.type == 'fun') {
				defineValue(_ast.name, _ast)
				var_count++
			}
			if (_ast.type === 'assign') {
				setValue(_ast.variable, expression(_ast.value))
			}
			if (_ast.type === 'if') {
				judge(_ast)
			}
			if (_ast.type === 'while') {
				loop(_ast)
			}
			if (_ast.type === 'funcall') {
				funcall(_ast)
			}
			if (_ast.type === 'print') {
				print(_ast)
			}
		}
		if (reserve) {
			return var_count
		}
		//释放变量
		while (var_count > 0) {
			stack.pop()
			var_count--
		}
	}

	function vm(ast, callback) {
		_calllback = callback
		stack = []
		program(ast)
	}
	Vm = vm
})()
